/**
 * Copyright (c) 2016-2019 人人开源 All rights reserved.
 * <p>
 * https://www.renren.io
 * <p>
 * 版权所有，侵权必究！
 */

package io.renren.modules.app.controller;


import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.wxpay.sdk.MyWxPayConfig;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import io.renren.common.utils.R;
import io.renren.common.validator.ValidatorUtils;
import io.renren.modules.app.annotation.Login;
import io.renren.modules.app.entity.OrderEntity;
import io.renren.modules.app.entity.UserEntity;
import io.renren.modules.app.form.*;
import io.renren.modules.app.service.OrderService;
import io.renren.modules.app.service.UserService;
import io.renren.modules.app.utils.JwtUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.Getter;
import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * APP登录授权
 *
 * @author Mark sunlightcs@gmail.com
 */
@RestController
@RequestMapping("/app/wx/")
@Api("微信业务接口")
@SuppressWarnings("all")
@Slf4j
public class WxController {
    @Autowired
    private UserService userService;
    @Autowired
    private JwtUtils jwtUtils;

    @Value("${application.app-id}")
    private String appId;

    @Value("${application.app-secret}")
    private String appSecret;

    @Value("${application.key}")
    private String key;

    @Value("${application.mch-id}")
    private String mchId;

    @Autowired
    private OrderService orderService;

    @Autowired
    private MyWxPayConfig myWxPayConfig;

    /**
     * 登录
     */
    @PostMapping("login")
    @ApiOperation("登录")
    public R login(@RequestBody WxLoginForm form) {
        //表单校验
        ValidatorUtils.validateEntity(form);

        String url = "https://api.weixin.qq.com/sns/jscode2session";
        HashMap map = new HashMap();
        map.put("appid", appId);
        map.put("secret", appSecret);
        map.put("js_code", form.getCode());
        map.put("grant_type", "authorization_code");
        String response = HttpUtil.post(url, map);
        JSONObject json = JSONUtil.parseObj(response);
        String openid = json.getStr("openid");
        if (openid == null || openid.length() == 0) {
            return R.error("临时登陆凭证错误");
        }

        UserEntity user = new UserEntity();
        user.setOpenId(openid);
        QueryWrapper wrapper = new QueryWrapper(user);
        int count = userService.count(wrapper);
        if (count == 0) {
            user.setNickname(form.getNickname());
            user.setPhoto(form.getPhoto());
            user.setType(2);
            user.setCreateTime(new Date());
            userService.save(user);
        }
        user = new UserEntity();
        user.setOpenId(openid);
        wrapper = new QueryWrapper(user);
        user = userService.getOne(wrapper);
        long id = user.getUserId();
        String token = jwtUtils.generateToken(id);

        Map<String, Object> resmap = new HashMap<>();
        resmap.put("token", token);
        resmap.put("expire", jwtUtils.getExpire());

        return R.ok(resmap);
    }

    @Login
    @PostMapping("microAppPayOrder")
    @ApiOperation("小程序付款")
    public R microAppPayOrder(@RequestBody PayOrderForm form, @RequestHeader HashMap headers) {
        ValidatorUtils.validateEntity(form);
        String token = headers.get("token").toString();
        Long userId = Long.parseLong(jwtUtils.getClaimByToken(token).getSubject());
        int orderId = form.getOrderId();
        UserEntity user = new UserEntity();
        user.setUserId(userId);
        QueryWrapper wrapper = new QueryWrapper(user);
        int count = userService.count(wrapper);
        if (count == 0) {
            return R.error("用户不存在");
        }
        String openId = userService.getOne(wrapper).getOpenId();

        OrderEntity order = new OrderEntity();
        order.setUserId(userId.intValue());
        order.setId(orderId);
        order.setStatus(1); //查询未付款的状态
        wrapper = new QueryWrapper(order);
        count = orderService.count(wrapper);
        if (count == 0) {
            return R.error("不是有效订单");
        }

        //验证购物券是否有效
        //验证团购活动是否有效

        order = new OrderEntity();
        order.setId(orderId);
        wrapper = new QueryWrapper(order);
        order = orderService.getOne(wrapper);
        //向微信平台发出请求，创建支付订单
        String amount = order.getAmount().multiply(new BigDecimal(100)).intValue() + "";
        try {
            WXPay wxPay = new WXPay(myWxPayConfig);
            HashMap map = new HashMap();
            map.put("nonce_str", WXPayUtil.generateNonceStr());
            map.put("body", "订单备注");
            String orderNew = order.getCode() + UUID.randomUUID().toString().replace("-","").substring(0,5);
            map.put("out_trade_no", order.getCode());
            map.put("total_fee", amount);
            map.put("spbill_create_ip", "127.0.0.1");
            map.put("notify_url", "https://www.baidu.com");
            map.put("trade_type", "JSAPI");
            map.put("openid", openId);
            Map<String, String> result = wxPay.unifiedOrder(map);
            String prepayId = result.get("prepay_id");
            log.error("prepayId:{}", prepayId);
            if (prepayId != null) {
                order.setPrepayId(prepayId);
                UpdateWrapper updateWrapper = new UpdateWrapper();
                updateWrapper.eq("id", order.getId());
                orderService.update(order, updateWrapper);
                //数字签名
                map.clear();
                map.put("appId", appId);
                String timeStamp = new Date().getTime() + "";
                map.put("timeStamp", timeStamp);
                String nonceStr = WXPayUtil.generateNonceStr();
                map.put("nonceStr", nonceStr);
                map.put("package", "prepay_id=" + prepayId);
                map.put("signType", "MD5");
                String paySign = WXPayUtil.generateSignature(map, key);
                return R.ok().put("package", "prepay_id=" + prepayId)
                        .put("timeStamp", timeStamp)
                        .put("nonceStr", nonceStr)
                        .put("paySign", paySign);

            } else {
                return R.error("支付订单创建失败");
            }

        } catch (Exception e) {
            e.printStackTrace();
            return R.error("微信支付模块故障");
        }


    }

    @RequestMapping("receiveMessage")
    public void receiveMessage(HttpServletRequest request, HttpServletResponse response) throws Exception {
        request.setCharacterEncoding("utf-8");
        Reader reader = request.getReader();
        BufferedReader buff = new BufferedReader(reader);
        String line = buff.readLine();
        StringBuffer temp = new StringBuffer();
        while (line != null) {
            temp.append(line);
            line = buff.readLine();
        }
        buff.close();
        reader.close();
        Map<String, String> map = WXPayUtil.xmlToMap(temp.toString());
        String resultCode = map.get("result_code");
        String returnCode = map.get("return_code");
        if ("SUCCESS".equals(resultCode) && "SUCCESS".equals(returnCode)) {
            String outTradeNo = map.get("out_trade_no");
            UpdateWrapper wrapper = new UpdateWrapper();
            wrapper.eq("code",outTradeNo);
            wrapper.set("status",2); //2 已付款
            orderService.update(wrapper);
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/xml");
            PrintWriter writer = response.getWriter();
            BufferedWriter bufferedWriter = new BufferedWriter(writer);
            bufferedWriter.write("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
            bufferedWriter.close();
            writer.close();

        }


    }

    @Login
    @PostMapping("updateOrderStatus")
    @ApiOperation("更新商品订单状态")
    public R updateOrderStatus(@RequestBody UpdateOrderStatusForm form,
                               @RequestHeader HashMap headers){
        ValidatorUtils.validateEntity(form);
        String token = headers.get("token").toString();
        int userId = Integer.parseInt(jwtUtils.getClaimByToken(token).getSubject());
        int orderId = form.getOrderId();
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setUserId(userId);
        orderEntity.setId(orderId);
        QueryWrapper wrapper = new QueryWrapper(orderEntity);
        int count = orderService.count(wrapper);
        if (count == 0 ){
            return R.error("用户与订单不匹配");
        }
        //向微信平台发送请求，确定支付的状态  CX0000000120160522lhgfddlsjfd  prePayid = wx30170657238048de9e055ab377cf9c0000
        orderEntity = orderService.getOne(wrapper);
        String code = orderEntity.getCode();
        HashMap map = new HashMap();
        map.put("appid",appId);
        map.put("mch_id",mchId);
        map.put("out_trade_no",code);
        map.put("nonce_str",WXPayUtil.generateNonceStr());
        try {
            String sign = WXPayUtil.generateSignature(map,key);
            map.put("sign",sign);
            WXPay wxPay = new WXPay(myWxPayConfig);
            Map<String,String> result = wxPay.orderQuery(map);
            String resultCode = result.get("result_code");
            String returnCode = result.get("return_code");
            if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {
                String tradeState = result.get("trade_state");
                if ("SUCCESS".equals(tradeState)){
                    //用户付款成功
                    UpdateWrapper updateWrapper = new UpdateWrapper();
                    updateWrapper.eq("code",code);
                    updateWrapper.set("status",2); //2 已付款
                    updateWrapper.set("payment_type",1);
                    orderService.update(updateWrapper);
                    return R.ok("订单状态已经修改");
                }else {
                    return R.ok("订单状态未修改");
                }

            }
            return R.ok("订单状态未修改");

        } catch (Exception e) {
            e.printStackTrace();
            return R.error("查询支付订单失败");
        }

    }

    @PostMapping("nativePayOrder")
    @ApiOperation("native付款")
    public R nativeAppPayOrder(@RequestBody PayOrderForm form, @RequestHeader HashMap headers) {
        ValidatorUtils.validateEntity(form);
        String token = headers.get("token").toString();
        Long userId = Long.parseLong(jwtUtils.getClaimByToken(token).getSubject());
        int orderId = form.getOrderId();
        UserEntity user = new UserEntity();
        user.setUserId(userId);
        QueryWrapper wrapper = new QueryWrapper(user);
        int count = userService.count(wrapper);
        if (count == 0) {
            return R.error("用户不存在");
        }

        OrderEntity order = new OrderEntity();
        order.setUserId(userId.intValue());
        order.setId(orderId);
        order.setStatus(1); //查询未付款的状态
        wrapper = new QueryWrapper(order);
        count = orderService.count(wrapper);
        if (count == 0) {
            return R.error("不是有效订单");
        }

        //验证购物券是否有效
        //验证团购活动是否有效

        order = new OrderEntity();
        order.setId(orderId);
        wrapper = new QueryWrapper(order);
        order = orderService.getOne(wrapper);
        //向微信平台发出请求，创建支付订单
        String amount = order.getAmount().multiply(new BigDecimal(100)).intValue() + "";
        try {
            WXPay wxPay = new WXPay(myWxPayConfig);
            HashMap map = new HashMap();
            map.put("nonce_str", WXPayUtil.generateNonceStr());
            map.put("body", "订单备注Native");
            String orderNew = order.getCode() + UUID.randomUUID().toString().replace("-","").substring(0,5);
            map.put("out_trade_no", order.getCode());
            map.put("total_fee", amount);
            map.put("spbill_create_ip", "127.0.0.1");
            map.put("notify_url", "http://hardy1314.natapp1.cc/renren-fast/app/wx/receiveMessage");
            map.put("trade_type", "NATIVE");
            String sign = WXPayUtil.generateSignature(map,key);
            map.put("sign",sign);
            Map<String, String> result = wxPay.unifiedOrder(map);
            String prepayId = result.get("prepay_id");
            log.error("prepayId:{}", prepayId);
            String codeUrl = result.get("code_url"); //生成二维码的URL，非常重要
            if (prepayId != null) {
                order.setPrepayId(prepayId);
                UpdateWrapper updateWrapper = new UpdateWrapper();
                updateWrapper.eq("id", order.getId());
                orderService.update(order, updateWrapper);
                return R.ok().put("codeUrl",codeUrl);
            } else {
                return R.error("支付订单创建失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("微信支付模块故障");
        }
    }

    @GetMapping("qrcode")
    public void qrcode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String codeUrl = request.getParameter("codeUrl");
        if (codeUrl != null && codeUrl.length() > 0){
            QrConfig qrConfig = new QrConfig();
            qrConfig.setWidth(250);
            qrConfig.setHeight(250);
            qrConfig.setMargin(2);
            OutputStream out = response.getOutputStream();
            QrCodeUtil.generate(codeUrl,qrConfig,"jpg",out);
            out.close();
        }
    }

    @Login
    @PostMapping("searchOrderStatus")
    @ApiOperation("查询支付订单状态")
    public R searchOrderStatus(@RequestBody SearchOrderStatusForm form,
                               @RequestHeader HashMap headers){
        ValidatorUtils.validateEntity(form);
        String token = headers.get("token").toString();
        int userId = Integer.parseInt(jwtUtils.getClaimByToken(token).getSubject());
        int orderId = form.getOrderId();
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setUserId(userId);
        orderEntity.setId(orderId);
        QueryWrapper wrapper = new QueryWrapper(orderEntity);
        int count = orderService.count(wrapper);
        if (count == 0 ){
            return R.error("用户与订单不匹配");
        }
        orderEntity = orderService.getOne(wrapper);
        String code = orderEntity.getCode();
        HashMap map = new HashMap();
        map.put("appid",appId);
        map.put("mch_id",mchId);
        map.put("out_trade_no",code);
        map.put("nonce_str",WXPayUtil.generateNonceStr());
        try {
            String sign = WXPayUtil.generateSignature(map,key);
            map.put("sign",sign);
            WXPay wxPay = new WXPay(myWxPayConfig);
            Map<String,String> result = wxPay.orderQuery(map); //微信平台查询支付的状态
            String resultCode = result.get("result_code");
            String returnCode = result.get("return_code");
            if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {
                String tradeState = result.get("trade_state");
                if ("SUCCESS".equals(tradeState)){
                    //用户付款成功
                    UpdateWrapper updateWrapper = new UpdateWrapper();
                    updateWrapper.eq("code",code);
                    updateWrapper.set("status",2); //2 已付款
                    updateWrapper.set("payment_type",1);
                    orderService.update(updateWrapper);
                    return R.ok("订单状态已经修改");
                }else {
                    return R.ok("订单状态未修改");
                }
            }
            return R.ok("订单状态未修改");
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("查询支付订单失败");
        }
    }


    @PostMapping("scanCodePayOrder")
    @ApiOperation("付款码付款")
    @Login
    public R ScanCodePayOrder(@RequestBody ScanCodePayOrderForm form, @RequestHeader HashMap headers) {
        ValidatorUtils.validateEntity(form);
        String token = headers.get("token").toString();
        Long userId = Long.parseLong(jwtUtils.getClaimByToken(token).getSubject());
        int orderId = form.getOrderId();
        UserEntity user = new UserEntity();
        user.setUserId(userId);
        QueryWrapper wrapper = new QueryWrapper(user);
        int count = userService.count(wrapper);
        if (count == 0) {
            return R.error("用户不存在");
        }
        OrderEntity order = new OrderEntity();
        order.setUserId(userId.intValue());
        order.setId(orderId);
        order.setStatus(1); //查询未付款的状态
        wrapper = new QueryWrapper(order);
        count = orderService.count(wrapper);
        if (count == 0) {
            return R.error("不是有效订单");
        }
        //todo 验证购物券是否有效
        //todo 验证团购活动是否有效

        order = new OrderEntity();
        order.setId(orderId);
        wrapper = new QueryWrapper(order);
        order = orderService.getOne(wrapper);
        //向微信平台发出请求，创建支付订单
        String amount = order.getAmount().multiply(new BigDecimal(100)).intValue() + "";
        try {
            WXPay wxPay = new WXPay(myWxPayConfig);
            HashMap map = new HashMap();
            map.put("appid",appId);
            map.put("mch_id",mchId);
            map.put("nonce_str", WXPayUtil.generateNonceStr());
            map.put("body", "订单备注autoCode");
            String orderNew = order.getCode() + UUID.randomUUID().toString().replace("-","").substring(0,5);
            map.put("out_trade_no", order.getCode());
            map.put("total_fee", amount);
            map.put("spbill_create_ip", "127.0.0.1");
            map.put("auth_code",form.getAuthCode());
            String sign = WXPayUtil.generateSignature(map,key);
            map.put("sign",sign);
            Map<String, String> result = wxPay.microPay(map);
            /*
              1 为了防止，有些付款码支付需要输入密码，所以需要再次查询一下订单结果
             */
            result = wxPay.orderQuery(map);
            String resultCode = result.get("result_code");
            String returnCode = result.get("return_code");
            if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)){
                String prepayId = result.get("transaction_id");
                order.setPrepayId(prepayId);
                order.setStatus(2);
                order.setPaymentType(1);
                UpdateWrapper updateWrapper = new UpdateWrapper();
                updateWrapper.eq("id", order.getId());
                orderService.update(order, updateWrapper);
                return R.ok("付款成功");
            }
            else {
                return R.error("付款失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("微信支付模块故障");
        }
    }

}
